import bind from './helpers/bind'
const toString = Object.prototype.toString;

/**判断是否为数组 */
export function isArray(val) {
    return toString.call(val) === '[object Array]';
}

/**兼容数组和对象的forEach */
export function forEach(obj: any, fn: (val: any, key?: string, obj?: any) => void) {
    // Don't bother if no value provided
    if (obj === null || typeof obj === 'undefined') {
        return;
    }

    // Force an array if not already something iterable
    if (typeof obj !== 'object') {
        /*eslint no-param-reassign:0*/
        obj = [obj];
    }

    if (isArray(obj)) {
        // Iterate over array values
        for (var i = 0, l = obj.length; i < l; i++) {
            fn.call(null, obj[i], i, obj);
        }
    } else {
        // Iterate over object keys
        for (var key in obj) {
            if (Object.prototype.hasOwnProperty.call(obj, key)) {
                fn.call(null, obj[key], key, obj);
            }
        }
    }
}

/**判断是否为纯对象 */
export function isPlainObject(val: any): boolean {
    if (toString.call(val) !== '[object Object]') {
        return false;
    }

    var prototype = Object.getPrototypeOf(val);
    return prototype === null || prototype === Object.prototype;
}

/**合并多个对象 */
export function merge(...args/* obj1, obj2, obj3, ... */) {
    var result = {};
    function assignValue(val: any, key: string) {
        if (isPlainObject(result[key]) && isPlainObject(val)) {
            result[key] = merge(result[key], val);
        } else if (isPlainObject(val)) {
            result[key] = merge({}, val);
        } else if (isArray(val)) {
            result[key] = val.slice();
        } else {
            result[key] = val;
        }
    }

    for (var i = 0, l = arguments.length; i < l; i++) {
        forEach(arguments[i], assignValue);
    }
    return result;
}
/**判断是否为undefinded */
export function isUndefined(val: any): boolean {
    return typeof val === 'undefined';
}

/**
 * 判断是否为Buffer
 * @param val 
 */
export function isBuffer(val: any): boolean {
    return val !== null && !isUndefined(val) && val.constructor !== null && !isUndefined(val.constructor)
        && typeof val.constructor.isBuffer === 'function' && val.constructor.isBuffer(val);
}

/**
 * 判断是否为FormData
 * @param val 
 */
export function isFormData(val: any): boolean {
    return (typeof FormData !== 'undefined') && (val instanceof FormData);
}

/**
 * 是否为ArrayBufferView
 * @param val 
 */
export function isArrayBufferView(val: any): boolean {
    var result;
    if ((typeof ArrayBuffer !== 'undefined') && (ArrayBuffer.isView)) {
        result = ArrayBuffer.isView(val);
    } else {
        result = (val) && (val.buffer) && (val.buffer instanceof ArrayBuffer);
    }
    return result;
}

export function isArrayBuffer(val: any): boolean {
    return toString.call(val) === '[object ArrayBuffer]';
}

export function isStream(val: any): boolean {
    return isObject(val) && isFunction(val.pipe);
}

export function isObject(val: any): boolean {
    return val !== null && typeof val === 'object';
}

export function isFunction(val: any): boolean {
    return toString.call(val) === '[object Function]';
}

export function isFile(val: any): boolean {
    return toString.call(val) === '[object File]';
}

export function isBlob(val: any): boolean {
    return toString.call(val) === '[object Blob]';
}

export function isURLSearchParams(val: any): boolean {
    return typeof URLSearchParams !== 'undefined' && val instanceof URLSearchParams;
}

export function isDate(val: any): boolean {
    return toString.call(val) === '[object Date]';
}

export function isNumber(val: any): boolean {
    return typeof val === 'number';
}
export function isString(val) {
    return typeof val === 'string';
}

export function trim(str: string): string {
    return str.replace(/^\s*/, '').replace(/\s*$/, '');
}

/**
 * a 继承 b
 * @param a 继承对象
 * @param b 被继承对象
 * @param thisArg this上下文
 */
export function extend(a: any, b: any, thisArg?: any): any {
    forEach(b, function assignValue(val, key) {
        if (thisArg && typeof val === 'function') {
            a[key] = bind(val, thisArg);
        } else {
            a[key] = val;
        }
    });
    return a;
}

/**
 * 判断是否为标准浏览器
 */
export function isStandardBrowserEnv() {
    if (typeof navigator !== 'undefined' && (navigator.product === 'ReactNative' ||
        navigator.product === 'NativeScript' ||
        navigator.product === 'NS')) {
        return false;
    }
    return (
        typeof window !== 'undefined' &&
        typeof document !== 'undefined'
    );
}